package com.cscec81.passport.base.cas.configuration;

import lombok.extern.slf4j.Slf4j;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;
import java.util.List;

@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
@EnableConfigurationProperties({CasProperties.class, WhiteListProperties.class})
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

  //认证
  @Resource
  private CasAuthenticationProvider authenticationProvider;

  //认证点
  @Resource
  private CasAuthenticationEntryPoint authenticationEntryPoint;

  @Resource
  private CasAuthenticationSuccessHandler casAuthenticationSuccessHandler;

  //登出过滤
  @Resource
  private LogoutFilter logoutFilter;

  //单点登出
  @Resource
  private SingleSignOutFilter singleSignOutFilter;

  //cas配置
  @Resource
  private CasProperties casProperties;

  @Resource
  private WhiteListProperties whiteListProperties;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration corsConfiguration = new CorsConfiguration();
    corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);
    corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);
    corsConfiguration.addAllowedOriginPattern(CorsConfiguration.ALL);
    corsConfiguration.setAllowCredentials(true);
    source.registerCorsConfiguration("/**", corsConfiguration);

    List<String> whiteList = whiteListProperties.getWhitelist();
    log.info("白名单： {}",whiteList.size());
    log.info("白名单： {}",whiteList.toString());
    http
      .cors().configurationSource(source)
      .and()
      .csrf().disable()
      .exceptionHandling()
      .authenticationEntryPoint(authenticationEntryPoint)
      .and()
      .authorizeRequests(authorizeRequests -> {
        for (String s : whiteList) {
          authorizeRequests.antMatchers(s).permitAll();
          log.info(s);
        }
        authorizeRequests.antMatchers("/swagger-ui/**","/swagger-resources/**", "/v3/**").permitAll();
        authorizeRequests.antMatchers("/actuator/**", "/instances/**").permitAll();
        authorizeRequests.anyRequest().authenticated();
      })
      //添加认证过滤(这里我遇到一个坑，如果通过注入方式加入，会出现循环依赖问题)
      .addFilter(casAuthenticationFilter())
      //登出过滤
      .addFilterBefore(logoutFilter, LogoutFilter.class)
      //单点登出过滤
      .addFilterBefore(singleSignOutFilter, CasAuthenticationFilter.class);
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    log.info("cas认证");
    //认证方式
    auth.authenticationProvider(authenticationProvider);
  }

  @Bean
  public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
    //过滤器配置
    CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
    //使用security的认证管理
    casAuthenticationFilter.setAuthenticationManager(authenticationManager());
    //拦截登录接口
    casAuthenticationFilter.setFilterProcessesUrl(casProperties.getClientLogin());
    //配置认证成功跳转
    casAuthenticationFilter.setAuthenticationSuccessHandler(casAuthenticationSuccessHandler);

    return casAuthenticationFilter;
  }
}

